package com.apes.framework.plugin.esb.parser.element;

import com.apes.framework.api.SpringManager;
import com.apes.framework.plugin.esb.processor.ActionProcessor;
import com.apes.framework.plugin.esb.processor.ChainProcessor;
import com.apes.framework.plugin.filereader.xml.ApesElement;
import com.apes.framework.util.Tools;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;


/**
 * 功能：action元素解析器
 *
 * @author xul
 * @create 2018-04-16 14:25
 */
@Component
public class ActionElementParser extends AbstractProcessorParser {

    /**
     * 可解析的元素列表
     **/
    private final String[] elementNames = {"action"};

    /**
     * 功能：可解析的元素列表
     */
    @Override
    public String[] getNames() {
        return elementNames;
    }

    @Override
    <T extends Class> T getChainProcessorClass() {
        return (T) ActionProcessor.class;
    }

    @Override
    public ChainProcessor parse(ApesElement element) {
        final String component = element.getAttribute("component");
        Assert.notNull(component, this.getClass().getName() + ": 组件名参数不允许为空。");
        String methodName = element.getAttribute("method");
        Assert.notNull(methodName, this.getClass().getName() + ": 方法名参数不允许为空。");
        String parameterTypes = element.getAttribute("parameterTypes");
        List<ActionProcessor> chainProcessors = parse(component, methodName);
        ChainProcessor processor = getProcessor(chainProcessors, parameterTypes);
        if (processor == null && chainProcessors.size() == 1 && StringUtils.isEmpty(parameterTypes)) {
            return chainProcessors.get(0);
        }
        if (processor == null) {
            throw new RuntimeException(component + "." + methodName + ": 方法无效。");
        }
        return processor;
    }

    public static ActionProcessor getProcessor(List<ActionProcessor> chainProcessors, String parameterTypes) {
        try {
            String key = StringUtils.isEmpty(parameterTypes) ? "void" : parameterTypes;
            return chainProcessors.stream().filter(processor -> processor.getParameterTypes().equalsIgnoreCase(key)).findFirst().get();
        } catch (Exception e) {
            return null;
        }
    }

    private List<ActionProcessor> parse(String component, String methodName) {
        Object target = getBean(component);
        List<ActionProcessor> chainProcessors = new ArrayList<>();
        ReflectionUtils.doWithMethods(target.getClass(), new ReflectionUtils.MethodCallback() {
            @Override
            public void doWith(Method method) throws IllegalArgumentException {
                ReflectionUtils.makeAccessible(method);
                if (method.getParameterTypes().length <= 1) {
                    setProcessor(method);
                }
            }

            private void setProcessor(Method method) {
                String parameterTypes = Tools.getParameterTypes(method.getParameterTypes());
                ActionProcessor actionProcessor = getProcessor(chainProcessors, parameterTypes);
                if (actionProcessor != null) {
                    return;
                }
                actionProcessor = new ActionProcessor();
                actionProcessor.setTarget(target);
                actionProcessor.setMethod(method);
                chainProcessors.add(actionProcessor);
            }
        }, method -> method.getName().equals(methodName));
        Assert.isTrue(!chainProcessors.isEmpty(), target.getClass() + "." + methodName + ": 方法无效。");
        return chainProcessors;
    }

    private Object getBean(String name) {
        Object target = SpringManager.getBean(name);
        Assert.notNull(target, this.getClass().getName() + ": " + name + " 在spring容器中没有定义。");
        return target;
    }

    private static String componentWithMethod(String component, String method) {
        return component + "#" + method;
    }
}
